﻿//-----------------------------------------------------------------------
// <copyright file="UpdateHttpErrorSetting.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation.  All rights reserved.
// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY 
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
// </copyright>
// <summary> Allows update access to the URI and type for a Custom Error page</summary>
//-----------------------------------------------------------------------
namespace Microsoft.Sdc.Tasks.Web.WebSite
{
    using System;
    using Microsoft.Sdc.Tasks.Configuration.Web;
    using Microsoft.Build.Framework;

    /// <summary>
    /// Allows update access to the URI and type for a Custom Error page
    /// </summary>
    /// <remarks>
    /// A complete sample will be made available shortly
    /// </remarks>    
    public class UpdateHttpErrorSetting : TaskBase
    {
        private string directoryName = String.Empty;
        private int errorCode;
        private string subErrorCode = String.Empty;
        private string uri;
        private string type = string.Empty;
        private IisDirectoryType directoryType;
        private string machineName = "localhost";
        private string webSiteName = "Default Web Site";
        private string path = null;

        /// <summary>
        /// IisDirectoryType
        /// </summary>
        public enum IisDirectoryType
        {
            /// <summary>
            /// VirtualWebDir
            /// </summary>
            VirtualWebDir,

            /// <summary>
            /// WebDir
            /// </summary>
            WebDir
        }

        /// <summary>
        /// Number of HTTP error code that you want to update the custom error page for
        /// </summary>
        /// <value>A valid http error code that IIS allows custom error page setting for</value>
        [Required]
        public int ErrorCode
        {
            get { return this.errorCode; }
            set { this.errorCode = value; }
        }

        /// <summary>
        /// Number of the sub error code that you want to update the custom error page for.
        /// e.g. HTTP 403.2 error code will be 403 and the sub error code "3"
        /// </summary>
        /// <value>A valid machine name. If this value is not set the delete will 
        /// target on the local machine.</value>
        /// <remarks>This value allows string because "*" is a valid value and used when using the top
        /// level error code e.g. </remarks>
        public string SubErrorCode
        {
            get { return (this.subErrorCode ?? "*"); }
            set { this.subErrorCode = value; }
        }

        /// <summary>
        /// The location of the custom error page
        /// </summary>
        /// <value>A file location or a URL depending on
        /// whether the Type is "File" or "URL"</value>
        public string Uri
        {
            get { return this.uri; }
            set { this.uri = value; }
        }

        /// <summary>
        /// The type of the custom error page
        /// </summary>
        /// <value>The type of custom error page value can be either "File" or "URL"</value>
        public string Type
        {
            get { return this.type; }
            set { this.type = value; }
        }

        /// <summary>
        /// The type of the folder that the Custom Errors settings hang off
        /// </summary>
        /// <value>Value can be either "</value>
        [Required]
        public string DirectoryType
        {
            get { return this.directoryType.ToString(); }
            set { this.directoryType = (IisDirectoryType)Enum.Parse(this.directoryType.GetType(), value); }
        }

        /// <summary>
        /// Machine to perform the action on
        /// </summary>
        /// <value>A valid machine name. If this value is not set the delete will 
        /// target on the local machine.</value>
        public string MachineName
        {
            get { return (this.machineName ?? String.Empty); }
            set { this.machineName = value; }
        }

        /// <summary>
        /// Web site to unload the virtual directory's application from
        /// </summary>
        /// <value>A value web site name. If this value is not set the delete will
        /// target against "Default Web Site"</value>
        public string WebSiteName
        {
            get { return (this.webSiteName ?? String.Empty); }
            set { this.webSiteName = value; }
        }

        /// <summary>
        /// Path to the directory that the Custom Errors settings in question hang off
        /// </summary>
        /// <value>A path to the directory in the format "Path1\Path2\Path3\Path4", or "." to specify the entire web-site</value>
        /// <remarks>Use of this property, when the DirectoryType is VirtualWebDir, is invalid</remarks>
        public string Path
        {
            get { return this.path; }
            set { this.path = value; }
        }

        /// <summary>
        /// Gets or sets the name of the directory.
        /// </summary>
        /// <value>The name of the directory.</value>
        public string DirectoryName
        {
            get { return this.directoryName; }

            set { this.directoryName = value; }
        }

        /// <summary>
        /// Performs the action of this task.
        /// </summary>
        protected override void InternalExecute()
        {
            if (this.directoryType == UpdateHttpErrorSetting.IisDirectoryType.VirtualWebDir && this.Path != null)
            {
                // The path property has been set yet we are set to work with a Virtual Directory
                // This is not currently supported
                throw new NotSupportedException("Setting the Path property whilst having a DirectoryType of VirtualWebDir is not a currently support mode of operation");
            }

            if (this.directoryType == UpdateHttpErrorSetting.IisDirectoryType.WebDir && this.Path == null)
            {
                throw new NullReferenceException("The path property is null, this must be supplied when working with a DirectoryType of WebDir");
            }

            VirtualDirectory vdir;
            WebSite web = WebSite.Load(this.MachineName, this.WebSiteName);
            HttpErrorCollection httpErrors = null;
            if (this.directoryType == UpdateHttpErrorSetting.IisDirectoryType.VirtualWebDir)
            {
                vdir = web.VirtualDirectories[this.DirectoryName];
                if (vdir != null)
                {
                    httpErrors = vdir.HttpErrors;
                }
                else
                {
                    throw new ArgumentException("The DirectoryName passed in was invalid, the Virtual Directory could not be found");
                }
            }
            else
            {
                // Access the site-level error settings
                if (this.Path.Equals("."))
                {
                    httpErrors = web.Root.HttpErrors;
                }
                else
                {
                    string[] pathParts = this.Path.Split(new char[] { '\\' });
                    WebDirectory webDirectory = web.WebDirectories[pathParts[0]];
                    for (int pathDepth = 1; pathDepth <= (pathParts.Length - 1); pathDepth++)
                    {
                        webDirectory = webDirectory.WebDirectories[pathParts[pathDepth]];
                    }

                    httpErrors = webDirectory.WebDirectories[directoryName].HttpErrors;
                }

                if (httpErrors == null)
                {
                    throw new ArgumentException("The DirectoryName passed in was invalid, the Web Directory could not be found");
                }
            }

            HttpError httpError = httpErrors.GetHttpErrorFromErrorCode(this.ErrorCode, this.SubErrorCode);

            if (this.Type != null)
            {
                httpError.Type = this.Type;
            }

            if (this.Uri != null)
            {
                httpError.Uri = this.Uri;
            }

            httpErrors.Save(httpErrors.Parent);

            httpErrors.Parent.CommitChanges();
        }
    }
}